 function dist(r1,r2,w,lo,hi,d,goals,         tmp) {
    if ((r1,r2) in _D) 
        return _D[r1,r2]
    tmp = d0(r1,r2,lo,hi,d,goals,w)
    return _D[r1,r2] = _D[r2,r1] = tmp
 }
 function d0(r1,r2,lo,hi,d,goals,w,    \
            half,a,b,c,max,min,sum,n,tmp) {
    if(r1==r2) return 0
    for(c in w) {
        if (c in goals) continue
        n++
        a  = d[r1][c]
        b  = d[r2][c]
        tmp = 1
        if (a == b) {
             if (a != "?") tmp = 0
        } else # different non-nums are always 1
            if (c in hi) {
                max = hi[c]
                min = lo[c]
                if (max == min) tmp =  0
                else {
                    half = (max - min)/2
                    if (a == "?") a = b > half ? min : max
                    if (b == "?") b = a > half ? min : max
                    a = (a - min) / (max - min)
                    b = (b - min) / (max - min)
                    tmp = a - b }}
        sum += w[c]*tmp^2
    }
    return sqrt(sum)/sqrt(n)
 }
